package com.mlnx.ecg.ui.panels;

import com.mlnx.ecg.ui.config.ECGConfig;
import com.mlnx.ecg.ui.config.ECGDeviceConstant;
import com.mlnx.ecg.ui.databuffer.RealEcgDatabuffer;
import com.mlnx.ecg.ui.model.Channel;
import com.mlnx.ecg.ui.model.WavePos;
import com.mlnx.ecg.ui.style.WaveStyle;
import com.mlnx.ecg.ui.view.WaveView;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

public class RealEcgPanel extends JPanel implements EcgPanel {

    private List<WaveView> waveViews = new ArrayList<>();

    private boolean showGridding = true;

    private Channel channel;

    private Channel customChannel;

    private EcgShowType ecgShowType = EcgShowType._1x12;

    private float mmPermV = ECGDeviceConstant.DEFAULT_SCALE; // mm/mv

    private float mmPerS = ECGDeviceConstant.DEFAULT_SPEED; // mm/s

    private boolean draw = false;

    private RealEcgDatabuffer realEcgDatabuffer;

    public RealEcgPanel(EcgShowType ecgShowType, float mmPermV, float mmPerS) {
        super();
        this.realEcgDatabuffer = new RealEcgDatabuffer();
        this.ecgShowType = ecgShowType;
        this.mmPermV = mmPermV;
        this.mmPerS = mmPerS;

        addComponentListener(new EcgComponentListener());
        addListener();
    }

    public void setCustomChannel(Channel customChannel) {
        setChannel(customChannel);
        this.customChannel = customChannel;
    }

    public synchronized void initWaveView() {

        if (getHeight() == 0 || getWidth() == 0)
            return;

        setEcgShowType(ecgShowType, false);

        if (customChannel != null) {
            setChannel(customChannel);
        }

        repaint();
    }

    public synchronized void setMagnitude(float mmPermV, float mmPerS) {
        this.mmPermV = mmPermV;
        this.mmPerS = mmPerS;

        initWaveView();
    }

    public synchronized void setShowGridding(boolean showGridding) {
        this.showGridding = showGridding;

        if (waveViews != null && waveViews.size() > 0) {
            for (WaveView waveView : waveViews) {
                waveView.setShowGridding(showGridding);
            }
        }
    }

    public synchronized void setEcgShowType(EcgShowType ecgShowType,
                                            Boolean vLeadAsV5) {
        this.ecgShowType = ecgShowType;

        waveViews.clear();

        if (ecgShowType.equals(EcgShowType._1x1)) {
            ecgShowType = EcgShowType._1x12;
        }

        for (int i = 0; i < 12; ++i) {
            WaveView waveView = new WaveView(EcgShowType.getWavePos(
                    ecgShowType, i, getWidth(), getHeight()), i,
                    ECGConfig.ECGLEADNAMES.get(i), 500, mmPermV, mmPerS);
            waveView.setShowGridding(showGridding);

            waveViews.add(waveView);

        }

        if (ecgShowType.equals(EcgShowType._4x3)) {
            WaveView waveView = new WaveView(EcgShowType.getWavePos(
                    this.ecgShowType, -1, getWidth(), getHeight()), 0,
                    ECGConfig.ECGLEADNAMES.get(0), 500, mmPermV, mmPerS);

            waveView.setShowGridding(showGridding);
            waveViews.add(waveView);
        }

        if (this.ecgShowType.equals(EcgShowType._1x1)) {
            Channel channel = new Channel();
            channel.setChannelFlag(new boolean[]{false, true, false, false,
                    false, false, false, false, false, false, false, false});
            setChannel(channel);
        }

        if (ecgShowType.equals(EcgShowType._1x7)) {
            Channel channel = new Channel();
            channel.setvLeadAsV5(vLeadAsV5);
            channel.setChannelFlag(new boolean[]{true, true, true, true,
                    true, true, true, false, false, false, false, false});
            setChannel(channel);
        }

    }

    public synchronized void setChannel(Channel channel) {

        this.channel = channel;

        waveViews.clear();

        List<WavePos> wavePoss = EcgShowType.getWavePos(channel, getWidth(),
                getHeight());
        List<Integer> list = channel.getSelectChannelFlag();
        for (int i = 0; i < list.size(); i++) {
            String ecgLeadName = ECGConfig.ECGLEADNAMES.get(list.get(i));
            if (channel.isvLeadAsV5() && ecgShowType.equals(EcgShowType._1x7)
                    && i == 6) {
                ecgLeadName = "V5";
            }

            WaveView waveView = new WaveView(wavePoss.get(i), list.get(i),
                    ecgLeadName, 500, mmPermV, mmPerS);
            waveView.setShowGridding(showGridding);
            waveViews.add(waveView);
        }
    }

    public void startDraw(final List<Float[]> mvData) {

        synchronized (RealEcgPanel.this) {
            if (waveViews != null && waveViews.size() > 0) {

                for (int i = 0; i < mvData.size(); i++) {

                    Float[] floats = mvData.get(i);
                    for (int j = 0; j < waveViews.size(); j++) {
                        if (waveViews.get(j).getFlag() == i) {
                            for (int j2 = 0; j2 < floats.length; j2++) {

                                if (floats[j2] != null) {
                                    waveViews.get(j).updatePoint(floats[j2]);
                                } else {
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }

        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                repaint();
            }
        });

    }

    public void inputEcgData(byte[] data) {
        realEcgDatabuffer.inputEcgData(data);
    }

    public void stopDraw() {
        draw = false;
        realEcgDatabuffer = null;
    }

    public void drawEcg() {
        if (draw)
            return;

        boolean auto = true;
        boolean first = true;
        draw = true;

        long lastTime = -1;
        int diffMillisecond;

        List<Float[]> outputData;

        while (draw) {
            long currTime = System.currentTimeMillis();

            if (lastTime != -1) {
                diffMillisecond = (int) (currTime - lastTime);

                if (diffMillisecond > 2000) {
                    outputData = realEcgDatabuffer.outputEcgData(0, true, auto);
                    first = true;
                } else {

                    if (diffMillisecond % 2 != 0) {
                        diffMillisecond -= 1;
                        currTime -= 1;
                    }
                    outputData = realEcgDatabuffer.outputEcgData(
                            diffMillisecond, false, auto);
                }

            } else {
                outputData = realEcgDatabuffer.outputEcgData(0, true, auto);
            }

            if (outputData != null) {
                lastTime = currTime;
                startDraw(outputData);
            } else if (first) {
                lastTime = currTime;
                first = false;
            }

            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

    @Override
    public synchronized void paint(Graphics g) {
        super.paint(g);

        if (waveViews != null && waveViews.size() > 0) {
            for (WaveView waveView : waveViews) {
                waveView.doDraw((Graphics2D) g, true, WaveStyle.BG_COLOR,
                        WaveStyle.FRAME_COLOR, WaveStyle.TEXT_COLOR,
                        WaveStyle.ECG_COLOR);
            }
        }
    }

    private void addListener() {
        addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                super.mouseClicked(e);

                if (EcgShowType._4x3.equals(ecgShowType)) {

                    for (WaveView waveView : waveViews) {
                        if (waveView.isInRect(e.getX(), e.getY())) {
                            WaveView waveView2 = new WaveView(
                                    EcgShowType.getWavePos(ecgShowType, -1,
                                            getWidth(), getHeight()),
                                    waveView.getFlag(),
                                    ECGConfig.ECGLEADNAMES.get(waveView
                                            .getFlag()), 500, mmPermV, mmPerS);

                            waveView2.setShowGridding(showGridding);
                            waveViews.set(12, waveView2);

                            break;
                        }
                    }
                }
            }

        });
    }

    class EcgComponentListener implements ComponentListener {

        @Override
        public void componentResized(ComponentEvent e) {
            initWaveView();
        }

        @Override
        public void componentMoved(ComponentEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
        public void componentShown(ComponentEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
        public void componentHidden(ComponentEvent e) {
            // TODO Auto-generated method stub

        }

    }

}
